package com.crazyteam.genid.service.impl;


import com.crazyteam.genid.constant.GenIdConstant;
import com.crazyteam.genid.exception.BaseGenKeyException;
import com.crazyteam.genid.exception.GenPrimaryKeyException;
import com.crazyteam.genid.model.KeyBuffer;
import com.crazyteam.genid.model.KeyInfo;
import com.crazyteam.genid.service.GenerateKeyService;
import com.crazyteam.genid.service.PrimaryKeyService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @Desc
 * @Author guoyang
 * @CreateTime 2016-3-3 下午01:46:53
 */
@Service("generateKeyService")
public class GenerateKeyServiceImpl implements GenerateKeyService {

    @Autowired
    PrimaryKeyService primaryKeyService;

    public long nextPrimaryKey(final KeyInfo keyInfo){
        return nextPrimaryKey(keyInfo, GenIdConstant.INC_DEFAULT);
    }
    
    public long nextPrimaryKey(final KeyInfo keyInfo, Integer inc){
    	long value = GenIdConstant.UNDER_LIMIT;
    	// 修正步长
    	if (inc == null || inc <= 0) {
    		inc = GenIdConstant.INC_DEFAULT;
		}
        try {
            // 如果当前buff还有，锁住当前缓冲区后，则从当前buff拿取
            synchronized (keyInfo.currBuffLock) {
            	// 设置步长
            	keyInfo.getCurrBuff().setInc(inc);
            	
                if (keyInfo.getCurrBuff().hasNext()) {
                    value = keyInfo.getCurrBuff().nextValue();
                }else{
                    // 如果用完了
                    // 对所有缓冲区上锁
                    // 则需要将下一个缓冲区替换成当前的
                    // 取key
                    // 同步扩展
                    keyInfo.getCurrBuff().copy(primaryKeyService.expandCurrBuff(keyInfo));
                    if (keyInfo.getCurrBuff().hasNext()) {
                        value = keyInfo.getCurrBuff().nextValue();
                    }
                }
            }
            
            // 异步检查是否扩充缓冲区
            primaryKeyService.asynExpandKey(keyInfo);
        }catch (BaseGenKeyException e) {
            throw e;
        }catch (Exception e) {
            throw new GenPrimaryKeyException("gen primary exception", e);
        }

        if (value <= GenIdConstant.UNDER_LIMIT) {
            throw new GenPrimaryKeyException("gen primary exception");
        }

        return value;
    }

    public KeyInfo loadKeyInfo(final String primaryKeyName){
        // 查询新的主键缓冲区
        KeyBuffer keyBuff = primaryKeyService.loadBuff(primaryKeyName);
        KeyInfo keyInfo = new KeyInfo(primaryKeyName, keyBuff);
        // 异步读取预备缓冲区
        primaryKeyService.asynLoadPrepBuff(keyInfo);
        return keyInfo;
    }

}
